package updateinfoimpl

import (
	"encoding/xml"
	"errors"
	"fmt"
	"net/http"
	"regexp"
	"strings"

	"github.com/astaxie/beego"
	"github.com/klauspost/compress/zstd"
	"github.com/opensourceways/server-common-lib/utils"
)

var primaryRegexp = regexp.MustCompile(`title="(\w+-primary.xml.zst)"`)

type PrimaryXml struct {
	XMLName xml.Name         `xml:"metadata,omitempty"`
	Package []PrimaryPackage `xml:"package,omitempty"`
}

type PrimaryPackage struct {
	XMLName  xml.Name `xml:"package,omitempty"`
	Type     string   `xml:"type,attr"`
	Version  Version  `xml:"version,omitempty"`
	Location Location `xml:"location,omitempty"`
}

type Version struct {
	XMLName xml.Name `xml:"version,omitempty"`
	Epoch   string   `xml:"epoch,attr"`
}

type Location struct {
	XMLName xml.Name `xml:"location,omitempty"`
	Href    string   `xml:"href,attr"`
}

func (impl updateInfoImpl) getEpochOfRpm(branch, date, arch string) (map[string]string, error) {
	normalDir := fmt.Sprintf("%s/repo.openeuler.org/%s/%s/%s/repodata",
		beego.AppConfig.String("testResult::host"),
		branch, date, arch,
	)

	normalEpoch, err := impl.getEpochOfRpmByDir(normalDir)
	if err != nil {
		return nil, err
	}

	epolDir := fmt.Sprintf("%s/repo.openeuler.org/%s/EPOL/%s/main/%s/repodata",
		beego.AppConfig.String("testResult::host"),
		branch, date, arch,
	)

	epolEpoch, err := impl.getEpochOfRpmByDir(epolDir)
	if err != nil {
		impl.log.Errorf("get epoch of epol [%s %s %s] failed: %s", branch, date, arch, err.Error())
	}

	// 合并两个目录的数据
	for k, v := range epolEpoch {
		normalEpoch[k] = v
	}

	return normalEpoch, nil
}

func (impl updateInfoImpl) getEpochOfRpmByDir(dir string) (map[string]string, error) {
	primaryXmlContent, err := impl.getPrimaryXmlOfRepoData(dir)
	if err != nil {
		return nil, err
	}

	var primaryXml PrimaryXml
	if err = xml.Unmarshal(primaryXmlContent, &primaryXml); err != nil {
		return nil, err
	}

	epochOfRpm := make(map[string]string)
	for _, v := range primaryXml.Package {
		rpmName := strings.TrimPrefix(v.Location.Href, "Packages/")
		epochOfRpm[rpmName] = v.Version.Epoch
	}

	return epochOfRpm, nil
}

func (impl updateInfoImpl) getPrimaryXmlOfRepoData(urlOfDir string) (content []byte, err error) {
	client := utils.NewHttpClient(3)
	req, err := http.NewRequest(http.MethodGet, urlOfDir, nil)
	if err != nil {
		return
	}

	t, _, err := client.Download(req)
	if err != nil {
		err = fmt.Errorf("list dir %s failed: %s", urlOfDir, err.Error())
		return
	}

	match := primaryRegexp.FindAllStringSubmatch(string(t), -1)
	if len(match) == 0 {
		err = errors.New("not match primary xml")
		return
	}

	primaryFile := match[0][1]
	urlOfPrimaryFile := urlOfDir + "/" + primaryFile

	req, err = http.NewRequest(http.MethodGet, urlOfPrimaryFile, nil)
	fileContent, _, err := client.Download(req)
	if err != nil {
		err = fmt.Errorf("download file %s failed: %s", urlOfPrimaryFile, err.Error())
		return
	}

	d, _ := zstd.NewReader(nil)
	return d.DecodeAll(fileContent, content)
}
